/**
*********************************************************************************************************
*               Copyright(c) 2015, Realtek Semiconductor Corporation. All rights reserved.
*********************************************************************************************************
* @file      miot_model_server.c
* @brief     xiaomi vendor model server
* @details
* @author    hector_huang
* @date      2019-04-15
* @version   v1.0
* *********************************************************************************************************
*/
#include "miot_model.h"
#if MODEL_ENABLE_DELAY_MSG_RSP
#include "delay_msg_rsp.h"
#endif

#ifdef MI_MESH_ENABLED
/**
 * @brief default miot receive function
 * @param[in] pmesh_msg: received mesh message
 * @return process result
 */
static bool miot_server_receive(mesh_msg_p pmesh_msg)
{
    bool ret = FALSE;
    mesh_model_info_p pmodel_info = pmesh_msg->pmodel_info;

    if ((pmesh_msg->access_opcode & 0x0000FFFF) == 0x8F03){
        if (NULL != pmodel_info->model_data_cb)
        {
            pmodel_info->model_data_cb(pmodel_info, pmesh_msg->access_opcode, pmesh_msg);
            ret = TRUE;
        }
    }
    return ret;
}

bool miot_server_reg(uint8_t element_index, mesh_model_info_p pmodel_info)
{
    if (NULL == pmodel_info)
    {
        return FALSE;
    }

    pmodel_info->model_id = MESH_MODEL_MIOT_SERVER;
    if (NULL == pmodel_info->model_receive)
    {
        pmodel_info->model_receive = miot_server_receive;
        if (NULL == pmodel_info->model_data_cb)
        {
            printw("miot_server_reg: missing model data process callback!");
        }
    }
    return mesh_model_reg(element_index, pmodel_info);
}
#else
#include "mijia_mesh_publish.h"
mesh_msg_send_cause_t miot_status(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                  miot_payload_t *pdata, uint8_t len, uint32_t delay_time)
{
    if (len > MIOT_PARAM_MAX_LEN)
    {
        return MESH_MSG_SEND_CAUSE_PAYLOAD_SIZE_EXCEED;
    }
    miot_status_t msg;
    uint16_t msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_STATUS) + len;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_STATUS);
    memcpy(&msg.parameters, pdata, len);
    mi_publish_vendor_refresh(pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = msg_len;
    if (0 != dst)
    {
        mesh_msg.dst = dst;
        mesh_msg.app_key_index = app_key_index;
    }
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_event(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                  miot_event_payload_t *pdata, uint8_t len, uint32_t delay_time)
{
    miot_event_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_EVENT);
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_EVENT) + len;
    if (0 != dst)
    {
        mesh_msg.dst = dst;
        mesh_msg.app_key_index = app_key_index;
    }
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_event_tlv(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                  miot_event_tlv_payload_t *pdata, uint16_t len, uint32_t delay_time)
{
    if(len > MIOT_SEGMENT_MAX_LEN + 3)
        return MESH_MSG_SEND_CAUSE_PAYLOAD_SIZE_EXCEED;
    
    miot_event_tlv_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_EVENT_TLV);
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_EVENT_TLV) + len;
    if (0 != dst)
    {
        mesh_msg.dst = dst;
        mesh_msg.app_key_index = app_key_index;
    }
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_action_ack(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                  miot_action_payload_t *pdata, uint8_t len, uint32_t delay_time)
{
    miot_action_ack_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_ACTION_ACK);
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_ACTION_ACK) + len;
    if (0 != dst)
    {
        mesh_msg.dst = dst;
        mesh_msg.app_key_index = app_key_index;
    }
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_sub_status(const mesh_model_info_p pmodel_info, uint16_t dst,
                                      uint16_t app_key_index, uint16_t sub_addr, uint32_t delay_time)
{
    miot_sub_status_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_GW);
    msg.type = MIOT_MESH_CONFIG_TYPE_SUB_STATUS;
    msg.sub_addr = sub_addr;

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = sizeof(msg);
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_dev_discover_req(const mesh_model_info_p pmodel_info, uint16_t dst,
                                            uint16_t app_key_index, uint8_t tid, uint32_t delay_time)
{
    miot_dev_discover_req_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_NODE);
    msg.type = MIOT_MESH_CONFIG_TYPE_DEV_DISCOVER_REQ;
    msg.tid = tid;

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = sizeof(msg);
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_dev_discover_rsp(const mesh_model_info_p pmodel_info, uint16_t dst,
                                            uint16_t app_key_index, uint32_t delay_time)
{
    miot_dev_discover_rsp_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_GW);
    msg.type = MIOT_MESH_CONFIG_TYPE_DEV_DISCOVER_RSP;

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = sizeof(msg);
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_net_param_req(const mesh_model_info_p pmodel_info, uint16_t dst,
                                         uint16_t app_key_index, uint8_t tid, uint8_t retry_cnt, uint32_t delay_time)
{
    miot_net_param_req_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_GW);
    msg.type = MIOT_MESH_CONFIG_TYPE_NET_PARAM_REQ;
    msg.retry_cnt = retry_cnt;
    msg.tid = tid;

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = sizeof(msg);
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_net_param_rsp(const mesh_model_info_p pmodel_info, uint16_t dst,
                                         uint16_t app_key_index, uint8_t tid, uint8_t pub_interval, uint32_t delay_time)
{
    miot_net_param_rsp_t msg;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_NODE);
    msg.type = MIOT_MESH_CONFIG_TYPE_NET_PARAM_RSP;
    msg.pub_interval = pub_interval;
    msg.tid = tid;

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = sizeof(msg);
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_node_config_set(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                            uint8_t subtype, const uint8_t *pdata, uint8_t len, uint32_t delay_time)
{
    miot_node_config_set_t msg;
    uint16_t msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_MESH_CONFIG_TO_NODE) + len + 2;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_NODE);
    msg.type = MIOT_MESH_CONFIG_TYPE_NODE_CONFIG_SET;
    msg.subtype = subtype;
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = msg_len;
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_node_config_status(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                            uint8_t subtype, const uint8_t *pdata, uint8_t len, uint32_t delay_time)
{
    miot_node_config_status_t msg;
    uint16_t msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_MESH_CONFIG_TO_GW) + len + 2;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_MESH_CONFIG_TO_GW);
    msg.type = MIOT_MESH_CONFIG_TYPE_NODE_CONFIG_STATUS;
    msg.subtype = subtype;
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = msg_len;
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_publish(const mesh_model_info_p pmodel_info, miot_payload_t *pdata,
                                   uint8_t len)
{
    mesh_msg_send_cause_t ret = MESH_MSG_SEND_CAUSE_INVALID_DST;
    if (mesh_model_pub_check(pmodel_info))
    {
        ret = miot_status(pmodel_info, 0, 0, pdata, len, 0);
    }

    return ret;
}

mesh_msg_send_cause_t miot_sync_prop(const mesh_model_info_p pmodel_info, uint16_t dst, uint16_t app_key_index,
                                    miot_sync_payload_t *pdata, uint8_t len, uint32_t delay_time)
{
    if (len > MIOT_PARAM_MAX_LEN)
    {
        return MESH_MSG_SEND_CAUSE_PAYLOAD_SIZE_EXCEED;
    }
    miot_sync_t msg;
    uint16_t msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_SYNC_PROP) + len;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_SYNC_PROP);
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = msg_len;
    mesh_msg.dst = dst;
    mesh_msg.app_key_index = app_key_index;
    mesh_msg.delay_time = delay_time;
    return access_send(&mesh_msg);
}

mesh_msg_send_cause_t miot_indication(const mesh_model_info_p pmodel_info, uint16_t dst,
                                uint16_t app_key_index, const uint8_t *pdata, uint8_t len)
{
    if (len > MIOT_PARAM_MAX_LEN)
    {
        return MESH_MSG_SEND_CAUSE_PAYLOAD_SIZE_EXCEED;
    }
    miot_indication_t msg;
    uint16_t msg_len = ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_INDICATION) + len;
    ACCESS_OPCODE_BYTE(msg.opcode, MESH_MSG_MIOT_INDICATION);
    memcpy(&msg.parameters, pdata, len);

    mesh_msg_t mesh_msg;
    mesh_msg.pmodel_info = pmodel_info;
    access_cfg(&mesh_msg);
    mesh_msg.pbuffer = (uint8_t *)&msg;
    mesh_msg.msg_len = msg_len;
    if (0 != dst)
    {
        mesh_msg.dst = dst;
        mesh_msg.app_key_index = app_key_index;
    }
    return access_send(&mesh_msg);
}

/**
 * @brief default miot receive function
 * @param[in] pmesh_msg: received mesh message
 * @return process result
 */
static bool miot_server_receive(mesh_msg_p pmesh_msg)
{
    bool ret = TRUE;
    uint8_t *pbuffer = pmesh_msg->pbuffer + pmesh_msg->msg_offset;
    mesh_model_info_p pmodel_info = pmesh_msg->pmodel_info;

    switch (pmesh_msg->access_opcode)
    {
    case MESH_MSG_MIOT_GET:
        {
            miot_server_get_t get_data;
            get_data.src = pmesh_msg->src;
            get_data.dst = pmesh_msg->dst;
            get_data.app_key_index = pmesh_msg->app_key_index;
            if (pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_GET) > MIOT_PARAM_MAX_LEN)
            {
                printw("miot_server_receive: miot_get invilad lenth!");
                return false;
            }
            get_data.siid = *(pbuffer + MEMBER_OFFSET(miot_get_t, siid));
            get_data.piid = *(pbuffer + MEMBER_OFFSET(miot_get_t, piid));
            
            if (NULL != pmodel_info->model_data_cb)
            {
                pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_GET, &get_data);
            }
        }
        break;
    case MESH_MSG_MIOT_SET:
    case MESH_MSG_MIOT_SET_UNACK:
        {
            miot_server_set_t set_data;
            set_data.src = pmesh_msg->src;
            set_data.dst = pmesh_msg->dst;
            set_data.app_key_index = pmesh_msg->app_key_index;
            set_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_SET);
            if (set_data.param_len >= MIOT_PARAM_MAX_LEN){
                set_data.param_len = MIOT_PARAM_MAX_LEN;
                set_data.parameters.tid = *(pbuffer + MEMBER_OFFSET(miot_set_t, parameters)
                                            + MEMBER_OFFSET(miot_payload_t, tid));
                set_data.parameters.type = *(pbuffer + MEMBER_OFFSET(miot_set_t, parameters)
                                            + MEMBER_OFFSET(miot_payload_t, type));
            }else if (set_data.param_len != MIOT_PARAM_SHORT_LEN){
                printi("miot_server_receive: miot_set invilad lenth!");
                return false;
            }
            set_data.parameters.siid = *(pbuffer + MEMBER_OFFSET(miot_set_t, parameters)
                                        + MEMBER_OFFSET(miot_payload_t, siid));
            set_data.parameters.piid = *(pbuffer + MEMBER_OFFSET(miot_set_t, parameters)
                                        + MEMBER_OFFSET(miot_payload_t, piid));
            memcpy(set_data.parameters.value, pbuffer + MEMBER_OFFSET(miot_set_t, parameters)
                    + MEMBER_OFFSET(miot_payload_t, value), MIOT_VALUE_LEN);
            
            if (NULL != pmodel_info->model_data_cb)
            {
                if (pmesh_msg->access_opcode == MESH_MSG_MIOT_SET)
                {
                    pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_SET, &set_data);
                }
                else
                {
                    pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_SET_UNACK, &set_data);
                }
            }
        }
        break;
    case MESH_MSG_MIOT_SYNC_PROP_ACK:
        {
            miot_server_sync_ack_t sync_ack_data;
            sync_ack_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(
                                                MESH_MSG_MIOT_SYNC_PROP_ACK);
            if(sync_ack_data.param_len > MIOT_PARAM_MAX_LEN)
            {
                sync_ack_data.param_len = MIOT_PARAM_MAX_LEN;
            }
            memcpy(&sync_ack_data.parameters, pbuffer + MEMBER_OFFSET(miot_sync_ack_t, parameters),
                   sync_ack_data.param_len);
            if (NULL != pmodel_info->model_data_cb)
            {
                pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_SYNC_PROP_ACK, &sync_ack_data);
            }
        }
        break;
    case MESH_MSG_MIOT_INDICATION_ACK:
        {
            miot_server_indication_ack_t indication_ack_data;
            indication_ack_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(
                                                MESH_MSG_MIOT_INDICATION_ACK);
            if (indication_ack_data.param_len > MIOT_PARAM_MAX_LEN)
            {
                indication_ack_data.param_len = MIOT_PARAM_MAX_LEN;
            }
            memcpy(&indication_ack_data.parameters, pbuffer + MEMBER_OFFSET(miot_indication_ack_t, parameters),
                   indication_ack_data.param_len);
            if (NULL != pmodel_info->model_data_cb)
            {
                pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_INDICATION_ACK, &indication_ack_data);
            }
        }
        break;
    case MESH_MSG_MIOT_ACTION:
        {
            miot_server_action_t action_data;
            action_data.src = pmesh_msg->src;
            action_data.dst = pmesh_msg->dst;
            action_data.app_key_index = pmesh_msg->app_key_index;
            action_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(
                                                MESH_MSG_MIOT_ACTION);
            if (action_data.param_len > MIOT_PARAM_MAX_LEN)
            {
                action_data.param_len = MIOT_PARAM_MAX_LEN;
            }
            memcpy(&action_data.parameters, pbuffer + MEMBER_OFFSET(miot_action_t, parameters),
                   action_data.param_len);
            if (NULL != pmodel_info->model_data_cb)
            {
                pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_ACTION, &action_data);
            }
        }
        break;
    case MESH_MSG_MIOT_MESH_CONFIG_TO_NODE:
        {
            uint8_t type = *(pbuffer + ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_MESH_CONFIG_TO_NODE));
            switch (type)
            {

            case MIOT_MESH_CONFIG_TYPE_DEV_DISCOVER_REQ:
                {
                    /* send response */
                    uint32_t delay_rsp_time = 0;
#if MODEL_ENABLE_DELAY_MSG_RSP
                    delay_rsp_time = delay_msg_get_rsp_delay(pmesh_msg->dst);
#endif
                    miot_dev_discover_rsp(pmodel_info, pmesh_msg->src, pmesh_msg->app_key_index, delay_rsp_time);
                }
                break;
            case MIOT_MESH_CONFIG_TYPE_NODE_CONFIG_SET:
                {
                    miot_node_config_set_t *pdata = (miot_node_config_set_t *)pbuffer;
                    miot_server_node_config_t set_data;
                    set_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(
                                                MESH_MSG_MIOT_MESH_CONFIG_TO_NODE) - 2;
                    set_data.src = pmesh_msg->src;
                    set_data.dst = pmesh_msg->dst;
                    set_data.subtype = pdata->subtype;
                    memcpy(set_data.parameters, pbuffer + MEMBER_OFFSET(miot_node_config_set_t, parameters),
                        set_data.param_len);
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_NODE_COIFIG_SET, &set_data);
                    }
                }
                break;
            case MIOT_MESH_CONFIG_TYPE_NET_PARAM_RSP:
                {
                    miot_net_param_rsp_t *pdata = (miot_net_param_rsp_t *)pbuffer;
                    miot_server_net_param_rsp_t rsp_data;
                    rsp_data.src = pmesh_msg->src;
                    rsp_data.dst = pmesh_msg->dst;
                    rsp_data.tid = pdata->tid;
                    rsp_data.pub_interval = pdata->pub_interval;
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_NET_PARAM_RSP, &rsp_data);
                    }
                }
                break;
            default:
                break;
            }
        }
        break;
    case MESH_MSG_MIOT_MESH_CONFIG_TO_GW:
        {
            uint8_t type = *(pbuffer + ACCESS_OPCODE_SIZE(MESH_MSG_MIOT_MESH_CONFIG_TO_GW));
            switch (type)
            {
            case MIOT_MESH_CONFIG_TYPE_SUB_STATUS:
                {
                    miot_sub_status_t *pdata = (miot_sub_status_t *)pbuffer;
                    miot_server_sub_status_t status_data;
                    status_data.src = pmesh_msg->src;
                    status_data.dst = pmesh_msg->dst;
                    status_data.primary_grp_addr = pdata->sub_addr;
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_SUB_STATUS, &status_data);
                    }
                }
                break;
            case MIOT_MESH_CONFIG_TYPE_DEV_DISCOVER_RSP:
                {
                    //miot_dev_discover_rsp_t *pdata = (miot_dev_discover_rsp_t *)pbuffer;
                    miot_server_dev_discover_rsp_t rsp_data;
                    rsp_data.src = pmesh_msg->src;
                    rsp_data.dst = pmesh_msg->dst;
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_DEV_DISCOVER_RSP, &rsp_data);
                    }
                }
                break;
            case MIOT_MESH_CONFIG_TYPE_NODE_CONFIG_STATUS:
                {
                    miot_node_config_status_t *pdata = (miot_node_config_status_t *)pbuffer;
                    miot_server_node_config_t status_data;
                    status_data.param_len = pmesh_msg->msg_len - ACCESS_OPCODE_SIZE(
                                                MESH_MSG_MIOT_MESH_CONFIG_TO_GW) - 2;
                    status_data.src = pmesh_msg->src;
                    status_data.dst = pmesh_msg->dst;
                    status_data.subtype = pdata->subtype;
                    memcpy(status_data.parameters, pbuffer + MEMBER_OFFSET(miot_node_config_status_t, parameters),
                        status_data.param_len);
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_NODE_COIFIG_STATUS, &status_data);
                    }
                }
                break;
            case MIOT_MESH_CONFIG_TYPE_NET_PARAM_REQ:
                {
                    miot_net_param_req_t *pdata = (miot_net_param_req_t *)pbuffer;
                    miot_server_net_param_req_t req_data;
                    req_data.src = pmesh_msg->src;
                    req_data.dst = pmesh_msg->dst;
                    req_data.tid = pdata->tid;
                    req_data.retry_cnt = pdata->retry_cnt;
                    if (NULL != pmodel_info->model_data_cb)
                    {
                        pmodel_info->model_data_cb(pmodel_info, MIOT_SERVER_NET_PARAM_REQ, &req_data);
                    }
                }
                break;
            default:
                break;
            }
        }
        break;
    default:
        ret = FALSE;
        break;
    }
    return ret;
}

bool miot_server_reg(uint8_t element_index, mesh_model_info_p pmodel_info)
{
    if (NULL == pmodel_info)
    {
        return FALSE;
    }

    pmodel_info->model_id = MESH_MODEL_MIOT_SERVER;
    if (NULL == pmodel_info->model_receive)
    {
        pmodel_info->model_receive = miot_server_receive;
        if (NULL == pmodel_info->model_data_cb)
        {
            printw("miot_server_reg: missing model data process callback!");
        }
    }

    return mesh_model_reg(element_index, pmodel_info);
}

bool node_config_flash_write(node_config_flash_param_type_t type, uint16_t len, void *pdata)
{
    uint32_t ret = 0;
    switch (type)
    {
    case MIOT_MESH_NODE_CONFIG_SYBTYPE_SCAN_PARM:
        {
            ret = ftl_save(pdata, NODE_CONFIG_FLASH_PARAMS_APP_OFFSET+ \
                            MEMBER_OFFSET(node_config_flash_param_t, scan_param), len);
        }
        break;
    case MIOT_MESH_NODE_CONFIG_SYBTYPE_MAGIC:
        {
            ret = ftl_save(pdata, NODE_CONFIG_FLASH_PARAMS_APP_OFFSET+ \
                            MEMBER_OFFSET(node_config_flash_param_t, magic), len);
        }
        break;
    default:
        printi("unknown type: %d!",type);
        break;
    }
    
    if (0 != ret)
    {
        printe("node_config_flash_write: failed, type = %d, cause = %d", type, ret);
    }
    return (0 == ret);
}

bool node_config_flash_read(node_config_flash_param_type_t type, uint16_t len, void *pdata)
{
    uint32_t ret = 0;
    switch (type)
    {
    case MIOT_MESH_NODE_CONFIG_SYBTYPE_SCAN_PARM:
        {
            ret = ftl_load(pdata, NODE_CONFIG_FLASH_PARAMS_APP_OFFSET+ \
                            MEMBER_OFFSET(node_config_flash_param_t, scan_param), len);
        }
        break;
    case MIOT_MESH_NODE_CONFIG_SYBTYPE_MAGIC:
        {
            ret = ftl_load(pdata, NODE_CONFIG_FLASH_PARAMS_APP_OFFSET+ \
                            MEMBER_OFFSET(node_config_flash_param_t, magic), len);
        }
        break;
    default:
        printi("unknown type: %d!",type);
        break;
    }
    
    if (0 != ret)
    {
        printe("node_config_flash_read: failed, type = %d, cause = %d", type, ret);
    }
    return (0 == ret);
}
#endif //#ifdef MI_MESH_ENABLED
